package com.study.reflection;

import org.junit.jupiter.api.Test;

import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.Arrays;

/**
 * @author: jzhou
 * @date: 2025/6/8-12:01
 * @version: 1.0
 * @description: juc-study
 */
public class ReflectionTest {
    // for 循环执行次数
    private static final int COUNT = 1000;

    @Test
    public void testClassFor() {
        // 1.通过类实例获取
        User user = new User();
        Class<? extends User> clazz1 = user.getClass();
        System.out.println("01 - " + clazz1);

        // 2.通过类直接调用class获取
        Class<User> clazz2 = User.class;
        System.out.println("02 - " + clazz2);

        // 3.通过Class.forName获取
        Class<?> clazz3 = null;
        try {
            clazz3 = Class.forName("com.study.reflection.User");
        } catch (ClassNotFoundException e) {
            // 当找不到指定类时，会抛出此异常
            e.printStackTrace();
        }
        System.out.println("03 - " + clazz3);

        // 4.通过类加载器获取
        ClassLoader classLoader = this.getClass().getClassLoader();
        Class<?> clazz4 = null;
        try {
            clazz4 = classLoader.loadClass("com.study.reflection.User");
        } catch (ClassNotFoundException e) {
            // 当找不到指定类时，会抛出此异常
            e.printStackTrace();
        }
        System.out.println("04 - " + clazz4);

        // hashCode相等，说明这四种方式获取的是同一个实例
        System.out.println("05 - " + clazz1.hashCode());
        System.out.println("06 - " + clazz2.hashCode());
        System.out.println("07 - " + clazz3.hashCode());
        System.out.println("08 - " + clazz4.hashCode());
    }

    @Test
    public void testClass() throws Exception {
        Class<?> clazz = Class.forName("com.study.reflection.User");

        // 获取该类所在包路径
        Package aPackage = clazz.getPackage();
        System.out.println("01 - " + aPackage);

        // 获取该类上所有注解
        Annotation[] declaredAnnotations = clazz.getDeclaredAnnotations();
        for (Annotation temp : declaredAnnotations) {
            System.out.println("02 - " + temp);
        }

        // 获取类上的修饰符
        int modifiers = clazz.getModifiers();
        String modifier = Modifier.toString(modifiers);
        System.out.println("03 - " + modifier);

        // 获取类名称
        String name = clazz.getName();
        System.out.println("04 - " + name);
        // 获取简单类名
        String simpleName = clazz.getSimpleName();
        System.out.println("05 - " + simpleName);

        // 获取直属超类
        Type genericSuperclass = clazz.getGenericSuperclass();
        System.out.println("06 - " + genericSuperclass);

        // 获取直属实现的接口
        Type[] genericInterfaces = clazz.getGenericInterfaces();
        for (Type temp : genericInterfaces) {
            System.out.println("07 - " + temp);
        }

    }

    @Test
    public void testConstructor() throws Exception {
        Class<?> clazz = Class.forName("com.study.reflection.User");

        // 获取一个声明为 public 构造函数实例
        Constructor<?> constructor1 = clazz.getConstructor(int.class, String.class, String.class);
        System.out.println("01 - " + constructor1);

        // 获取所有声明为 public 构造函数实例
        Constructor<?>[] constructorArray1 = clazz.getConstructors();
        for (Constructor<?> constructor : constructorArray1) {
            System.out.println("02 - " + constructor);
        }

        // 获取一个声明为 private 构造函数实例
        Constructor<?> constructor2 = clazz.getDeclaredConstructor(String.class);
        System.out.println("03 - " + constructor2);


        // 获取所有声明的构造函数实例
        Constructor<?>[] constructorArray2 = clazz.getDeclaredConstructors();
        for (Constructor<?> constructor : constructorArray2) {
            System.out.println("04 - " + constructor);
        }

        // 根据构造函数创建一个实例
        Object o1 = constructor1.newInstance(25, "杨过", "大侠");
        System.out.println("05 - " + o1);

        // 将构造函数的可访问标志设为 true 后，可以通过私有构造函数创建实例
        constructor2.setAccessible(true);
        Object o2 = constructor2.newInstance("小龙女");
        System.out.println("06 - " + o2);

        // 获取该构造函数上的所有注解
        Annotation[] annotations = constructor1.getDeclaredAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println("07 - " + annotation);
        }

        // 获取该构造函数上的所有参数类型
        Type[] genericParameterTypes = constructor1.getGenericParameterTypes();
        for (Type genericParameterType : genericParameterTypes) {
            System.out.println("08 - " + genericParameterType);
        }

    }



    @Test
    public void testInvoke() throws Exception {
        //根据包名获取class对象
        Class<?> c1 = Class.forName("com.study.reflection.User");



        //通过无参构造器获取对象
        User user = (User) c1.newInstance();
        System.out.println("通过无参构造器获取对象：反射获取的user:"+user);

        //通过有参构造器获取对象
        Constructor<?> declaredConstructor = c1.getDeclaredConstructor(int.class, String.class, String.class);
        User user1 = (User) declaredConstructor.newInstance(10, "jzhou", "程序员");
        System.out.println("通过有参构造器获取对象：反射获取的use1r:"+user1);

        //  --------------------   使用反射调用类的方法   ------------------------------

        //通过getDeclaredMethod获取方法对象   DeclaredMethod 翻译为：已声明的方法
        Method setName = c1.getDeclaredMethod("setName", String.class);
        //使用反射 invoke执行方法
        setName.invoke(user1,"j-zhou");
        System.out.println("反射执行useName："+user1.getName());
        System.out.println("通过 invoke 修改后的user1:"+user1);


        System.out.println("---------------华丽的分割线-------------");
        System.out.println(Arrays.toString(c1.getFields()));  // 只有public修饰的字段才能获取到
        System.out.println(Arrays.toString(c1.getMethods()));
        System.out.println(Arrays.toString(c1.getDeclaredFields()));
        System.out.println(Arrays.toString(c1.getDeclaredMethods()));


        //  --------------------   使用反射给类的属性赋值   ------------------------------
        System.out.println("---------------华丽的分割线-------------");

        User user3 = (User) c1.newInstance();

        Field name = c1.getDeclaredField("name");
        //权限检测，设置为true可以访问private方法 若不设置，can not access a member of class com.study.reflection.User with modifiers "private"
        name.setAccessible(true);
        name.set(user3,"张三");
        System.out.println("反射给name赋值："+user3.getName());


        test1();
        test2();
        test3();

    }

    //普通创建对象调用方法
    public static void test1(){
        User user  = new User();

        long start = System.currentTimeMillis();

        for (int i = 0; i < COUNT; i++) {
            user.getName();
        }

        long end = System.currentTimeMillis();

        System.out.println("new对象执行时间:"+(end-start)+"ms");
    }

    //使用反射调用方法
    public static void test2() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {

        Class aClass = Class.forName("com.study.reflection.User");

        User user = (User) aClass.newInstance();

        Method getName = aClass.getDeclaredMethod("getName", null);

        long start = System.currentTimeMillis();

        for (int i = 0; i < COUNT; i++) {
            getName.invoke(user,null);
        }

        long end = System.currentTimeMillis();

        System.out.println("反射对象执行时间:"+(end-start)+"ms");
    }

    //使用反射调用方法  开启访问权限
    public static void test3() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {

        Class aClass = Class.forName("com.study.reflection.User");

        User user = (User) aClass.newInstance();

        Method getName = aClass.getDeclaredMethod("getName");

        getName.setAccessible(true);

        long start = System.currentTimeMillis();

        for (int i = 0; i < COUNT; i++) {
            getName.invoke(user);
        }

        long end = System.currentTimeMillis();

        System.out.println("反射对象开启权限执行时间:"+(end-start)+"ms");

    }
}
